﻿/***************************************************************
 * 口口
 * 小地图控制器
 ***************************************************************/

using UnityEngine;
using UnityEngine.UI;
using WorldMapBase;
using XLua;

using UnityEngine.EventSystems;
using System.Collections.Generic;
using DG.Tweening;

namespace Yoozoo.Modules.MiniMap
{
    public class MiniMapController : MonoBehaviour
    {
        private RectTransform m_RectTransMap;// 小地图 点击范围
        private RectTransform m_RectTransMapBg;// 小地图背景 点击范围

        private Transform m_TransSelfPos;// 小地图上自己的位置信息
        private Transform m_TransMapView;// 小地图上视野框

        private Vector2 mapSize;
        private Camera uiCamera;
        private Vector3 touchPos;
        private LuaFunction mapViewReq;
        private LuaFunction mapViewMoveUpdate; // lua端及时更新lod5表现
        private float timer;
        private Vector2 lastPos;

        private float cos_45 = 0;
        private float sin_45 = 0;

        private Dictionary<long, GameObject> m_TransUnionPos = new Dictionary<long, GameObject>();// 联盟成员位置
        private Dictionary<long, GameObject> m_TransMarkPos = new Dictionary<long, GameObject>();// 联盟标记位置

        public float miniMapViewRectDis = 3.0f;

        private LineRenderer line = null;
        /// <summary>
        /// 按顺序画线点集，0-左上 1-右上 2-左下 3-右下
        /// </summary>
        private int[] m_ArraysLinePoints = new int[4]
            {0,1,3,2};

        private Vector3 viewCenter = Vector3.zero;

        private Vector3[] m_LinePoints = new Vector3[4] {
            Vector3.zero,Vector3.zero,Vector3.zero,Vector3.zero,
        };

        /// <summary>
        /// LUA中获取小地图实例设置给C#
        /// </summary>
        /// <param name="go"></param>
        public void SetTransform(GameObject go)
        {
            this.uiCamera = GetComponent<Camera>();
            this.touchPos = Vector3.zero;

            this.m_RectTransMap = go.transform.Find("page/mapRect").GetComponent<RectTransform>();
            this.m_RectTransMapBg = go.transform.Find("page/miniMapBg").GetComponent<RectTransform>();
            this.m_TransSelfPos = this.m_RectTransMap.GetChild(0);
            //this.m_TransMapView = this.m_RectTransMap.GetChild(1);

            this.mapSize = m_RectTransMap.rect.size;
            this.timer = 0;
            this.lastPos = Vector2.zero;
            sin_45 = Mathf.Sin(-45);
            cos_45 = Mathf.Cos(-45);

            this.line = m_RectTransMap.gameObject.GetOrAddComponent<LineRenderer>();
            line.startColor = Color.white;
            line.endColor = Color.white;
            line.positionCount = 4;

        }

        public void SetUnionPos(long id, Vector2 pos, Color c)
        {
            GameObject obj = null;
            m_TransUnionPos.TryGetValue(id, out obj);
            if (obj == null) obj = GetPosObj();
            if (obj)
            {
                // 设置位置
                //获取点在地图上的位置的比例
                float x = Mathf.Clamp01(pos.x / WorldMapConfigData.GetMapData().mapWidth);
                float y = Mathf.Clamp01(pos.y / WorldMapConfigData.GetMapData().mapHeight);

                var res = new Vector3((x - 0.5f) * this.mapSize.x, (y - 0.5f) * this.mapSize.y, 0);
                obj.transform.localPosition = res;
                // 设置颜色
                RawImage image = obj.GetComponent<RawImage>();
                if (image) image.color = c;

            }
            m_TransUnionPos[id] = obj;
        }

        public void SetMarkPos(long id, Vector2 pos)
        {
            GameObject obj = null;
            m_TransMarkPos.TryGetValue(id, out obj);
            if (obj == null) obj = GetPosObj();
            if (obj)
            {
                // 设置位置
                //获取点在地图上的位置的比例
                float x = Mathf.Clamp01(pos.x / WorldMapConfigData.GetMapData().mapWidth);
                float y = Mathf.Clamp01(pos.y / WorldMapConfigData.GetMapData().mapHeight);

                var res = new Vector3((x - 0.5f) * this.mapSize.x, (y - 0.5f) * this.mapSize.y, 0);
                obj.transform.localPosition = res;
                // 设置颜色
                RawImage image = obj.GetComponent<RawImage>();
                if (image) image.color = Color.red;

            }
            m_TransMarkPos[id] = obj;
        }

        private GameObject GetPosObj()
        {
            GameObject obj = null;
            if (m_TransSelfPos)
            {
                obj = GameObject.Instantiate(m_TransSelfPos.gameObject, m_TransSelfPos.parent);
            }
            return obj;
        }

        public void SetLuaTable(LuaTable table)
        {
            this.mapViewReq = table.GetLuaFunction("mapViewReq");
            this.mapViewMoveUpdate = table.GetLuaFunction("mapViewMoveUpdate");
        }

        /// <summary>
        /// 设置自己在小地图上的位置显示
        /// </summary>
        /// <param name="x">世界坐标x</param>
        /// <param name="y">世界坐标y</param>
        public void SetSelfPos(float x, float y)
        {
            Vector2 result = Vector2.zero;

            //获取点在地图上的位置的比例
            result.x = Mathf.Clamp01(x / WorldMapConfigData.GetMapData().mapWidth);
            result.y = Mathf.Clamp01(y / WorldMapConfigData.GetMapData().mapHeight);
            
            var pos = new Vector3((result.x - 0.5f) * this.mapSize.x, (result.y - 0.5f) * this.mapSize.y, 0);
            m_TransSelfPos.localPosition = pos;
        }

        public void SetAllPosShow(bool visible)
        {
            if (m_RectTransMap) m_RectTransMap.gameObject.SetActive(visible);
        }

        public void RemoveUnionPos(long id)
        {
            GameObject obj = null;
            m_TransUnionPos.TryGetValue(id, out obj);
            if (obj)
            {
                m_TransUnionPos.Remove(id);
                GameObject.Destroy(obj);
            }
        }

        public void RemoveAllUnionPos()
        {
            foreach (GameObject obj in m_TransUnionPos.Values)
            {
                if (obj) Destroy(obj);
            }
            m_TransUnionPos.Clear();
        }

        public void RemoveMarkPos(long id)
        {
            GameObject obj = null;
            m_TransMarkPos.TryGetValue(id, out obj);
            if (obj)
            {
                m_TransMarkPos.Remove(id);
                GameObject.Destroy(obj);
            }
        }

        public void RemoveAllMarkPos()
        {
            foreach (GameObject obj in m_TransMarkPos.Values)
            {
                if (obj) Destroy(obj);
            }
            m_TransMarkPos.Clear();
        }

        public void SetMiniMapViewScale(float scale)
        {
            //if (m_TransMapView)
            //{
            //    m_TransMapView.transform.localScale = Vector3.one * scale;
            //}
        }

        private void Update()
        {
            if (this.timer > 0)
            {
                this.timer -= Time.deltaTime;
                if (this.timer <= 0)
                    this.mapViewReq?.Action(this.lastPos.x, this.lastPos.y);
            }

            OnTouch();
            //OnUpdateViewPos();
            DrawLine();
        }

        private void OnUpdateViewPos()
        {
            Vector2 viewCenter = WorldCameraManager.GetInstance().GetLastCenterViewPosition();
            viewCenter.x = Mathf.Clamp01(viewCenter.x / WorldMapConfigData.GetMapData().mapWidth);
            viewCenter.y = Mathf.Clamp01(viewCenter.y / WorldMapConfigData.GetMapData().mapHeight);
            var pos = new Vector3((viewCenter.x - 0.5f) * this.mapSize.x, (viewCenter.y - 0.5f) * this.mapSize.y, 0);
            //m_TransMapView.localPosition = pos;
        }

        private void OnTouch()
        {
            if (!this.uiCamera || !Input.GetMouseButton(0))
                return;

            if (Input.mousePosition.x == this.touchPos.x && Input.mousePosition.y == this.touchPos.y)
                return;

            if (!this.IsOnMiniMap())
            {
                return;
            }
            Vector2 pos = Vector2.zero;
            this.touchPos.x = Input.mousePosition.x;
            this.touchPos.y = Input.mousePosition.y;
            Vector3 v33 = m_RectTransMapBg.InverseTransformPoint(Input.mousePosition);
            RectTransformUtility.ScreenPointToLocalPointInRectangle(m_RectTransMapBg, new Vector2(touchPos.x, touchPos.y), uiCamera, out Vector2 mPos);
            // m_RectTransMapBg的中心点是 整个地图的中心点
   
            float x = mPos.x * cos_45 - mPos.y * sin_45;
            float y = mPos.y * cos_45 + mPos.x * sin_45;
            var xRatio = x / this.mapSize.x;
            var yRatio = y / this.mapSize.y;
            pos = new Vector2((xRatio + 0.5f) * WorldMapConfigData.GetMapData().mapWidth,
                (yRatio + 0.5f) * WorldMapConfigData.GetMapData().mapHeight);

            // 强制更新地图
            WorldMap.WorldMapUtility.UpdateCenterViewPosition(pos);
            WorldMap.WorldMapUtility.UpdateViewRectForce();
            this.mapViewMoveUpdate?.Action(pos.x, pos.y);// 移动视野前 强制更新Lod5
            WorldCameraManager.FocusTo(pos, 0, Ease.Linear, null);
            this.timer = 0.5f;
            this.lastPos = pos;
        }

        private bool IsOnMiniMap()
        {
            PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
            pointerEventData.position = Input.mousePosition;
            List<RaycastResult> result = new List<RaycastResult>();
            EventSystem.current.RaycastAll(pointerEventData, result);
            for (int i = 0;i < result.Count;i++)
            {
                RaycastResult res = result[i];
                if (res.gameObject.name == "miniMapBg")
                {
                    return true;
                }
            }
            return false;
        }

        private float CheckPos(float value)
        {
            if (value < 0)
            {
                return 0;
            }
            if (value > WorldEntry.m_mapSize)
            {
                return WorldEntry.m_mapSize;
            }
            return value;
        }

        /// <summary>
        /// 画线
        /// </summary>
        private void DrawLine()
        {
            for (int i = 0; i < 4; i++)
            {
                Vector2 tmpFront = CaculatePosInMiniMap((int)m_ArraysLinePoints[i]);
                Vector3 v3 = m_LinePoints[i];
                v3.x = tmpFront.x;
                v3.y = tmpFront.y;
                m_LinePoints[i] = v3; 
            }
            CheckMiniDis();
            for (int i = 0; i < 4; i++)
            {
                Vector3 v3 = m_LinePoints[i];
                line.SetPosition(i, v3);
            }
        }

        private void CheckMiniDis()
        {
            if (miniMapViewRectDis > 0)
            {
                viewCenter.x = ((m_LinePoints[0].x + m_LinePoints[1].x) * 0.5f + (m_LinePoints[3].x + m_LinePoints[2].x) * 0.5f) * 0.5f;
                viewCenter.y = ((m_LinePoints[0].y + m_LinePoints[1].y) * 0.5f + (m_LinePoints[3].y + m_LinePoints[2].y) * 0.5f) * 0.5f;
                
                float dis_bl = Vector3.Distance(viewCenter, m_LinePoints[3]);
                if (dis_bl < miniMapViewRectDis && dis_bl > 0)
                {
                    // 计算梯形的中心 
					float radio = miniMapViewRectDis / dis_bl;
  
                    // 按照比例放大各点到中心的距离 从而放大梯形
					for (int i = 0; i < 4; i++)
					{
						Vector3 v3 = m_LinePoints[i];
						float dis_x = v3.x - viewCenter.x;
						float dis_y = v3.y - viewCenter.y;
                        v3.x += dis_x * radio;
                        v3.y += dis_y * radio;
                        m_LinePoints[i] = v3;
                    }
                }
            }
        }

        /// <summary>
        /// 计算点在小地图中的位置
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        private Vector2 CaculatePosInMiniMap(int index)
        {
            Vector2 result = Vector2.zero;

            Vector2 tmpRate = GetRateInWorldmap(index);

            var size = m_RectTransMap.rect.size;
            result.x = size.x * (tmpRate.x - 0.5f);
            result.y = size.y * (tmpRate.y - 0.5f);
            return result;
        }

        /// <summary>
        /// 获取点在地图上的位置的比例
        /// </summary>
        /// <param name="index">点的索引</param>
        /// <returns></returns>
        private Vector2 GetRateInWorldmap(int index)
        {
            Vector2 result = Vector2.zero;

            //点相对于地图的位置，地图左下角为（0，0）点
            Vector3 localToMap = WorldCameraManager.GetInstance().m_CornersPosition[index];
            //获取点在地图上的位置的比例
            result.x = Mathf.Clamp01(localToMap.x / WorldMapConfigData.GetMapData().mapWidth);
            result.y = Mathf.Clamp01(localToMap.z / WorldMapConfigData.GetMapData().mapHeight);
            return result;
        }
    }
}
